Setup
Initial
preperation
Connect to
database
# Not sure if necessary... was an issue with a version conflict... try new version in the future again...
# devtools::install_version("RPostgres", version = "1.2.1", repos = "http://cran.us.r-project.org")
### general options
Sys.setenv(LANG = "en")
options("scipen" = 100, "digits" = 4) # override R's tendency to use scientific notation
### Clean workspace
rm(list=ls())
graphics.off()
### Load packages (maybe need to be installed first)
# Standard
library(tidyverse) # General DS toolkit
library(magrittr) # For advanced piping
# Databases
library(DBI) # GEneral R database interface
library(RPostgres) # PostgreSQL interface driver
library(dbplyr) # for dplyr with databases
# networks
library(tidygraph)
library(ggraph)
library(ggrepel)
# Load functions
source("functions/functions_relatedness.R")
# Load script with variables
source("../variables.R")
# set up connection to existing PostgreSQL database, just plug in own details
con <- dbConnect(drv = RPostgres::Postgres(),
dbname = var_dbname,
host = var_host,
port = var_port,
user = var_user,
password = var_password,
sslmode = 'require'
)
rm(var_dbname, var_host, var_password, var_port, var_user)
Load data
# con %>% dbListTables() %>% sort()
Defining
parameters
# Regular tables
data_appln <- read_rds('../temp/data_appln.rds')
data_docdb_fam_cpc <- read_rds('../temp/data_docdb_fam_cpc.rds')
data_pers_appln <- read_rds('../temp/data_pers_appln.rds')
data_person <- read_rds('../temp/data_person.rds')
data_nace2 <- read_rds('../temp/data_nace2.rds')
# Adittional ones
g_tech <- read_rds('../temp/g_tech.rds')
region_RTA <- read_rds('../temp/region_RTA.rds')
region_tech <- read_rds('../temp/region_tech.rds')
n_regions = 7
cuttoff = 100
select_regions <- region_tech %>%
group_by(nuts) %>%
summarise(n = sum(weight_frac, na.rm = TRUE),
n_Y = sum(weight_frac * Y_tag, na.rm = TRUE)) %>%
ungroup() %>%
mutate(share_Y = n_Y / (n + n_Y)) %>%
filter(nuts %in% c('SE232', 'NO043', 'DK012')) %>%
arrange(desc(n_Y))
Patent application
development
# Restrict to top N regions
top_regions <- region_tech %>%
group_by(nuts) %>%
summarise(n = sum(weight_frac, na.rm = TRUE),
n_Y = sum(weight_frac * Y_tag, na.rm = TRUE)) %>%
ungroup() %>%
mutate(share_Y = n_Y / (n + n_Y)) %>%
#filter(n_Y >= cuttoff ) %>%
arrange(desc(n_Y)) %>%
slice(1:n_regions) %>%
bind_rows(select_regions) %>%
distinct()
data_appln %>%
count(appln_filing_year, Y_tag) %>%
ggplot(aes(x = appln_filing_year, y = n, col = Y_tag)) +
geom_line(key_glyph = "timeseries") +
labs(title = 'Patent applications: Development',
subtitle = 'All Nordic contries, by Y tag',
x = 'Year',
y = 'Number applications',
col = 'Green')

Texnology space
general
data_pers_appln %>%
semi_join(top_regions, by = 'nuts') %>%
count(appln_filing_year, nuts, Y_tag, wt = weight_frac) %>%
ggplot(aes(x = appln_filing_year, y = n, col = nuts)) +
geom_line(key_glyph = "timeseries") +
facet_wrap(vars(Y_tag), scales = 'free') +
labs(title = 'Patent applications: Development',
subtitle = 'All Nordic contries',
x = 'Year',
y = 'Number applications, by region and Y tag',
col = 'Nuts3')

set.seed(1337)
coords_tech <- g_tech %>% igraph::layout.fruchterman.reingold() %>% as_tibble()
colnames(coords_tech) <- c("x", "y")
Specialization
development
g_tech %N>%
mutate(nace_group_name = nace_group_name %>% str_trunc(50, side = 'right')) %>%
ggraph(layout = coords_tech) +
geom_edge_link(aes(width = weight), alpha = 0.5, colour = "grey") +
geom_node_point(aes(colour = nace_sec_name, size = dgr)) +
geom_node_text(aes(label = nace_group_name, size = dgr, filter = percent_rank(dgr) >= 0.5 ), repel = TRUE) +
theme_void() +
labs(title =paste('Technology Space (all Nordics)'),
subtitle = 'Nodes = NACE 2 Industries. Edges: Relatedness')

# dataframe with technology relatedness edgelist
tech_rel <- g_tech %E>%
mutate(from_nace = .N()$name[from],
to_nace = .N()$name[to]) %>%
as_tibble() %>%
mutate(from = from_nace %>% as.character(),
to = to_nace %>% as.character(),
pct_rank = weight %>% percent_rank()) %>%
arrange(from, to)
tech_rel %<>%
bind_rows(tech_rel %>%
rename(from_new = to, to_new = from) %>%
rename(from = from_new, to = to_new) %>%
relocate(from, to)) %>%
distinct(from, to, .keep_all = TRUE)
# Dataframe with regions and technology fields
tech_dev <- region_RTA %>%
select(period, nuts, nace_group, Y_tag, n_tech_region, rta, rta_bin) %>%
arrange(nuts, nace_group, Y_tag, period)
p1 <- region_RTA %>%
semi_join(top_regions, by = 'nuts') %>%
group_by(nuts, period, Y_tag) %>%
summarise(n_spec = rta_bin %>% sum(na.rm = TRUE),
n_spec_count = (n_tech_region * rta_bin) %>% sum(na.rm = TRUE),
HHI = sum((n_tech_region/sum(n_tech_region) * 100)^2) ) %>%
ungroup() %>%
#group_by(nuts, period) %>%
#summarise(Y_share = sum(Y_tag * n_spec, na.rm = TRUE) / sum(n_spec, na.rm = TRUE),
# Y_count = sum(Y_tag * n_spec_count, na.rm = TRUE)) %>%
#ungroup() %>%
mutate(nuts_period = paste(nuts, 'P', period)) %>%
pivot_wider(names_from = Y_tag, values_from = c(n_spec, n_spec_count, HHI), values_fill = 0, names_prefix = 'Y_tag_')
`summarise()` has grouped output by 'nuts', 'period'. You can override using the `.groups` argument.
p2 <- p1 %>%
select(period, nuts, n_spec_Y_tag_FALSE, n_spec_Y_tag_TRUE) %>%
pivot_wider(names_from = period, values_from = c(n_spec_Y_tag_FALSE, n_spec_Y_tag_TRUE))
p1 %>%
ggplot(aes(x = n_spec_Y_tag_FALSE, y = n_spec_Y_tag_TRUE)) +
geom_point(aes(size = n_spec_count_Y_tag_TRUE, col = HHI_Y_tag_TRUE)) +
geom_text(aes(label = nuts), position = position_dodge(0.9), alpha = 0.75) +
geom_segment(data = p2,
aes(x = n_spec_Y_tag_FALSE_1,
y = n_spec_Y_tag_TRUE_1,
xend = n_spec_Y_tag_FALSE_2,
yend = n_spec_Y_tag_TRUE_2,
size = 1),
alpha = 0.15,
arrow = arrow(length = unit(0.5, "cm"), type = "closed"),
show.legend = FALSE) +
scale_color_gradient2(low = "skyblue", mid = 'yellow', high = "red", midpoint = 1) +
labs(title = '',
subtitle = '',
note = '',
x = 'N non-green specializations',
y = 'N green specializations',
size = 'N green patents',
col = 'HHI green patents')

Analysis for existing
green paths:
rm(p2, p2)
Warning: object 'p2' not found
select_regions_green <- tech_dev %>%
group_by(nuts, period) %>%
summarise(green = sum(Y_tag * rta, na.rm = TRUE),
green_bin = sum(Y_tag * rta_bin, na.rm = TRUE),
n_tech_region = sum(n_tech_region, na.rm = TRUE),
n_green_region = sum(Y_tag * n_tech_region, na.rm = TRUE),
n_green_rta = sum(Y_tag * n_tech_region * rta_bin, na.rm = TRUE)) %>%
ungroup() %>%
filter(n_green_rta >= 100,
green_bin >= 1,
period == '1') %>%
select(nuts)
`summarise()` has grouped output by 'nuts'. You can override using the `.groups` argument.
tech_dev %<>%
group_by(nuts, nace_group, Y_tag) %>%
mutate(rta_dev = case_when(
rta_bin < lag(rta_bin, 1) ~ -1,
rta_bin == lag(rta_bin, 1) ~ 0,
rta_bin > lag(rta_bin, 1) ~ 1
)) %>%
ungroup()
tech_spec_dev <- tech_dev %>%
filter(n_tech_region >= 50) %>%
group_by(nuts, Y_tag) %>%
summarise(rta_dev = rta_dev %>% sum(na.rm = TRUE)) %>%
ungroup() %>%
pivot_wider(names_from = Y_tag, values_from = rta_dev, values_fill = 0, names_prefix = 'Y_spec_')
`summarise()` has grouped output by 'nuts'. You can override using the `.groups` argument.
tech_rel_dev <- tech_rel %>%
select(from, to, weight) %>%
left_join(tech_dev %>% distinct(nace_group, nuts), by = c('from' = 'nace_group')) %>%
# filter for rta in period 1
inner_join(tech_dev %>% filter(period == '1', rta_bin == 1) %>% select(nace_group, nuts, Y_tag), by = c('to' = 'nace_group', 'nuts')) %>%
# filter for new green specialization in period 2
semi_join(tech_dev %>% filter(period == '2', rta_bin == 1, rta_dev == 1, Y_tag == TRUE), by = c('from' = 'nace_group', 'nuts')) %>%
rename(nace_group = from, related_techn = to) %>%
group_by(nuts, nace_group, Y_tag) %>%
summarise(rel_max = weight %>% max(),
rel_sum = weight %>% sum(),
rel_mean = weight %>% mean()) %>%
ungroup()
`summarise()` has grouped output by 'nuts', 'nace_group'. You can override using the `.groups` argument.
tech_rel_dev %>%
group_by(nuts, Y_tag) %>%
summarise(rel = rel_max %>% mean()) %>%
ungroup() %>%
pivot_wider(names_from = Y_tag, values_from = rel, names_prefix = 'Y_', values_fill = 0) %>%
left_join(tech_dev %>% filter(Y_tag == TRUE, period == '2', rta_bin == 1) %>% select(nuts , n_tech_region) %>% count(nuts, wt = n_tech_region), by = c('nuts')) %>%
mutate(country = nuts %>% str_sub(1,2)) %>%
#semi_join(top_regions, by = 'nuts') %>%
filter(0.5 <= percent_rank(n)) %>%
ggplot(aes(x = Y_FALSE, y = Y_TRUE, size = n)) +
geom_point(aes(col = country)) +
geom_text_repel(aes(label = nuts), box.padding = 0.5, max.overlaps = Inf) +
labs(title = 'New green specialization period 2',
subtitle = 'By nuts regions',
note = 'Relatedness is the mean over all new green specializations, per green specialization largest relatedness to former specialization counted',
x = 'Relatedness non-green',
y = 'Relatedness green',
size = 'N green patents')
`summarise()` has grouped output by 'nuts'. You can override using the `.groups` argument.

- Label 2nd figure on green, label coinciding, maybe rta, share or
growth
Dataviz
tech_rel_dev %>%
group_by(nuts, nace_group, Y_tag) %>%
summarise(rel = rel_max %>% mean()) %>%
ungroup() %>%
pivot_wider(names_from = Y_tag, values_from = rel, names_prefix = 'Y_', values_fill = 0) %>%
left_join(tech_dev %>% filter(Y_tag == TRUE, period == '2', rta_bin == 1) %>% select(nuts, nace_group, n_tech_region) %>% count(nuts, nace_group, wt = n_tech_region), by = c('nuts', 'nace_group')) %>%
mutate(country = nuts %>% str_sub(1,2)) %>%
semi_join(top_regions, by = 'nuts') %>%
ggplot(aes(x = Y_FALSE, y = Y_TRUE, size = n)) +
geom_point() +
geom_text_repel(aes(label = nace_group), box.padding = 0.5) +
facet_wrap(vars(nuts)) +
labs(title = 'New green specialization period 2',
subtitle = 'By nuts regions',
note = 'Relatedness is the mean over all new green specializations, per green specialization largest relatedness to former specialization counted',
x = 'Relatedness non-green',
y = 'Relatedness green',
size = 'N green patents')
`summarise()` has grouped output by 'nuts', 'nace_group'. You can override using the `.groups` argument.

i = 1; place <- regions[i]
time = '1'
g_tech %N>%
left_join(region_RTA %>% filter(nuts == place, period == time) %>% select(techn_field_nr, rca, rca_Y, n_tech_region), by = c("name" = "techn_field_nr")) %>%
ggraph(layout = coords_tech) +
geom_edge_link(aes(width = weight), alpha = 0.2, colour = "grey") +
geom_node_point(aes(colour = rca, size = n_tech_region)) +
geom_node_text(aes(label = techn_field_name, size = rca, filter = rca >= 1), repel = TRUE) +
scale_color_gradient2(low = "skyblue", mid = 'yellow', high = "red", midpoint = 1) +
theme_graph() +
labs(title =paste("Technology Space:", place, 'Period', time, sep = " "),
subtitle = 'Nodes = Technology fields. Edges: Relatedness, Color = RTA')
LS0tCnRpdGxlOiAnR3JlZW4gUmVnaW9uYWwgUGF0aCBwYXBlcjogRGF0YXZpeicKYXV0aG9yOiAiRGFuaWVsIFMuIEhhaW4iCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWScpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDMKICAgIHRvY19mbG9hdDogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgY29kZV9mb2xkaW5nOiBoaWRlCi0tLQoKIyMgU2V0dXAKCmBgYHtyLCBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBOb3Qgc3VyZSBpZiBuZWNlc3NhcnkuLi4gd2FzIGFuIGlzc3VlIHdpdGggYSB2ZXJzaW9uIGNvbmZsaWN0Li4uIHRyeSBuZXcgdmVyc2lvbiBpbiB0aGUgZnV0dXJlIGFnYWluLi4uCiMgZGV2dG9vbHM6Omluc3RhbGxfdmVyc2lvbigiUlBvc3RncmVzIiwgdmVyc2lvbiA9ICIxLjIuMSIsIHJlcG9zID0gImh0dHA6Ly9jcmFuLnVzLnItcHJvamVjdC5vcmciKQoKIyMjIGdlbmVyYWwgb3B0aW9ucwpTeXMuc2V0ZW52KExBTkcgPSAiZW4iKQpvcHRpb25zKCJzY2lwZW4iID0gMTAwLCAiZGlnaXRzIiA9IDQpICMgb3ZlcnJpZGUgUidzIHRlbmRlbmN5IHRvIHVzZSBzY2llbnRpZmljIG5vdGF0aW9uCgojIyMgQ2xlYW4gd29ya3NwYWNlCnJtKGxpc3Q9bHMoKSkKZ3JhcGhpY3Mub2ZmKCkKCiMjIyBMb2FkIHBhY2thZ2VzIChtYXliZSBuZWVkIHRvIGJlIGluc3RhbGxlZCBmaXJzdCkKIyBTdGFuZGFyZApsaWJyYXJ5KHRpZHl2ZXJzZSkgIyBHZW5lcmFsIERTIHRvb2xraXQKbGlicmFyeShtYWdyaXR0cikgIyBGb3IgYWR2YW5jZWQgcGlwaW5nCgojIERhdGFiYXNlcwpsaWJyYXJ5KERCSSkgIyBHRW5lcmFsIFIgZGF0YWJhc2UgaW50ZXJmYWNlCmxpYnJhcnkoUlBvc3RncmVzKSAjIFBvc3RncmVTUUwgaW50ZXJmYWNlIGRyaXZlciAKbGlicmFyeShkYnBseXIpICMgZm9yIGRwbHlyIHdpdGggZGF0YWJhc2VzCgojIG5ldHdvcmtzCmxpYnJhcnkodGlkeWdyYXBoKQpsaWJyYXJ5KGdncmFwaCkKbGlicmFyeShnZ3JlcGVsKQoKIyBMb2FkIGZ1bmN0aW9ucwpzb3VyY2UoImZ1bmN0aW9ucy9mdW5jdGlvbnNfcmVsYXRlZG5lc3MuUiIpCmBgYAoKCgojIEluaXRpYWwgcHJlcGVyYXRpb24KCiMjIENvbm5lY3QgdG8gZGF0YWJhc2UKCmBgYHtyfQojIExvYWQgc2NyaXB0IHdpdGggdmFyaWFibGVzCnNvdXJjZSgiLi4vdmFyaWFibGVzLlIiKQoKIyBzZXQgdXAgY29ubmVjdGlvbiB0byBleGlzdGluZyBQb3N0Z3JlU1FMIGRhdGFiYXNlLCBqdXN0IHBsdWcgaW4gb3duIGRldGFpbHMKY29uIDwtIGRiQ29ubmVjdChkcnYgPSBSUG9zdGdyZXM6OlBvc3RncmVzKCksIAogICAgICAgICAgICAgICAgIGRibmFtZSA9IHZhcl9kYm5hbWUsCiAgICAgICAgICAgICAgICAgaG9zdCA9IHZhcl9ob3N0LCAKICAgICAgICAgICAgICAgICBwb3J0ID0gdmFyX3BvcnQsCiAgICAgICAgICAgICAgICAgdXNlciA9IHZhcl91c2VyLCAKICAgICAgICAgICAgICAgICBwYXNzd29yZCA9IHZhcl9wYXNzd29yZCwKICAgICAgICAgICAgICAgICBzc2xtb2RlID0gJ3JlcXVpcmUnCiAgICAgICAgICAgICAgICAgKQoKcm0odmFyX2RibmFtZSwgdmFyX2hvc3QsIHZhcl9wYXNzd29yZCwgdmFyX3BvcnQsIHZhcl91c2VyKQpgYGAKCmBgYHtyfQojIGNvbiAlPiUgZGJMaXN0VGFibGVzKCkgJT4lIHNvcnQoKQpgYGAKCiMjIExvYWQgZGF0YQoKYGBge3J9CiMgUmVndWxhciB0YWJsZXMKZGF0YV9hcHBsbiA8LSByZWFkX3JkcygnLi4vdGVtcC9kYXRhX2FwcGxuLnJkcycpCmRhdGFfZG9jZGJfZmFtX2NwYyA8LSByZWFkX3JkcygnLi4vdGVtcC9kYXRhX2RvY2RiX2ZhbV9jcGMucmRzJykKZGF0YV9wZXJzX2FwcGxuICA8LSByZWFkX3JkcygnLi4vdGVtcC9kYXRhX3BlcnNfYXBwbG4ucmRzJykKZGF0YV9wZXJzb24gPC0gcmVhZF9yZHMoJy4uL3RlbXAvZGF0YV9wZXJzb24ucmRzJykKZGF0YV9uYWNlMiA8LSByZWFkX3JkcygnLi4vdGVtcC9kYXRhX25hY2UyLnJkcycpCgojIEFkaXR0aW9uYWwgb25lcwpnX3RlY2ggPC0gcmVhZF9yZHMoJy4uL3RlbXAvZ190ZWNoLnJkcycpCnJlZ2lvbl9SVEEgPC0gcmVhZF9yZHMoJy4uL3RlbXAvcmVnaW9uX1JUQS5yZHMnKQpyZWdpb25fdGVjaCA8LSByZWFkX3JkcygnLi4vdGVtcC9yZWdpb25fdGVjaC5yZHMnKQpgYGAKCiMjIERlZmluaW5nIHBhcmFtZXRlcnMKCmBgYHtyfQpuX3JlZ2lvbnMgPSA3CmN1dHRvZmYgPSAxMDAKYGBgCgpgYGB7cn0Kc2VsZWN0X3JlZ2lvbnMgPC0gcmVnaW9uX3RlY2ggJT4lCiAgZ3JvdXBfYnkobnV0cykgJT4lCiAgc3VtbWFyaXNlKG4gPSBzdW0od2VpZ2h0X2ZyYWMsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIG5fWSA9IHN1bSh3ZWlnaHRfZnJhYyAqIFlfdGFnLCBuYS5ybSA9IFRSVUUpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKHNoYXJlX1kgPSBuX1kgLyAobiArIG5fWSkpICU+JQogIGZpbHRlcihudXRzICVpbiUgYygnU0UyMzInLCAnTk8wNDMnLCAnREswMTInKSkgJT4lCiAgYXJyYW5nZShkZXNjKG5fWSkpCmBgYAoKCgpgYGB7cn0KIyBSZXN0cmljdCB0byB0b3AgTiByZWdpb25zCnRvcF9yZWdpb25zIDwtIHJlZ2lvbl90ZWNoICU+JQogIGdyb3VwX2J5KG51dHMpICU+JQogIHN1bW1hcmlzZShuID0gc3VtKHdlaWdodF9mcmFjLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBuX1kgPSBzdW0od2VpZ2h0X2ZyYWMgKiBZX3RhZywgbmEucm0gPSBUUlVFKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShzaGFyZV9ZID0gbl9ZIC8gKG4gKyBuX1kpKSAlPiUKICAjZmlsdGVyKG5fWSA+PSBjdXR0b2ZmICkgJT4lCiAgYXJyYW5nZShkZXNjKG5fWSkpICU+JQogIHNsaWNlKDE6bl9yZWdpb25zKSAlPiUKICBiaW5kX3Jvd3Moc2VsZWN0X3JlZ2lvbnMpICU+JQogIGRpc3RpbmN0KCkKYGBgCgoKCgojIFBhdGVudCBhcHBsaWNhdGlvbiBkZXZlbG9wbWVudAoKYGBge3J9CmRhdGFfYXBwbG4gJT4lCiAgY291bnQoYXBwbG5fZmlsaW5nX3llYXIsIFlfdGFnKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBhcHBsbl9maWxpbmdfeWVhciwgeSA9IG4sIGNvbCA9IFlfdGFnKSkgKyAKICBnZW9tX2xpbmUoa2V5X2dseXBoID0gInRpbWVzZXJpZXMiKSArCiAgbGFicyh0aXRsZSA9ICdQYXRlbnQgYXBwbGljYXRpb25zOiBEZXZlbG9wbWVudCcsCiAgICAgICBzdWJ0aXRsZSA9ICdBbGwgTm9yZGljIGNvbnRyaWVzLCBieSBZIHRhZycsCiAgICAgICB4ID0gJ1llYXInLAogICAgICAgeSA9ICdOdW1iZXIgYXBwbGljYXRpb25zJywKICAgICAgIGNvbCA9ICdHcmVlbicpCmBgYApgYGB7cn0KZGF0YV9wZXJzX2FwcGxuICU+JQogIHNlbWlfam9pbih0b3BfcmVnaW9ucywgYnkgPSAnbnV0cycpICU+JQogIGNvdW50KGFwcGxuX2ZpbGluZ195ZWFyLCBudXRzLCBZX3RhZywgd3QgPSB3ZWlnaHRfZnJhYykgJT4lCiAgZ2dwbG90KGFlcyh4ID0gYXBwbG5fZmlsaW5nX3llYXIsIHkgPSBuLCBjb2wgPSBudXRzKSkgKyAKICBnZW9tX2xpbmUoa2V5X2dseXBoID0gInRpbWVzZXJpZXMiKSArCiAgZmFjZXRfd3JhcCh2YXJzKFlfdGFnKSwgc2NhbGVzID0gJ2ZyZWUnKSArCiAgbGFicyh0aXRsZSA9ICdQYXRlbnQgYXBwbGljYXRpb25zOiBEZXZlbG9wbWVudCcsCiAgICAgICBzdWJ0aXRsZSA9ICdBbGwgTm9yZGljIGNvbnRyaWVzJywKICAgICAgIHggPSAnWWVhcicsCiAgICAgICB5ID0gJ051bWJlciBhcHBsaWNhdGlvbnMsIGJ5IHJlZ2lvbiBhbmQgWSB0YWcnLAogICAgICAgY29sID0gJ051dHMzJykKYGBgCgojIFRleG5vbG9neSBzcGFjZSBnZW5lcmFsCgpgYGB7cn0Kc2V0LnNlZWQoMTMzNykKY29vcmRzX3RlY2ggPC0gZ190ZWNoICU+JSBpZ3JhcGg6OmxheW91dC5mcnVjaHRlcm1hbi5yZWluZ29sZCgpICU+JSBhc190aWJibGUoKQpjb2xuYW1lcyhjb29yZHNfdGVjaCkgPC0gYygieCIsICJ5IikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTE1LCBmaWcuaGVpZ2h0PSAxMH0KZ190ZWNoICVOPiUKICBtdXRhdGUobmFjZV9ncm91cF9uYW1lID0gbmFjZV9ncm91cF9uYW1lICU+JSBzdHJfdHJ1bmMoNTAsIHNpZGUgPSAncmlnaHQnKSkgJT4lCiAgZ2dyYXBoKGxheW91dCA9ICBjb29yZHNfdGVjaCkgKyAKICBnZW9tX2VkZ2VfbGluayhhZXMod2lkdGggPSB3ZWlnaHQpLCBhbHBoYSA9IDAuNSwgY29sb3VyID0gImdyZXkiKSArIAogIGdlb21fbm9kZV9wb2ludChhZXMoY29sb3VyID0gbmFjZV9zZWNfbmFtZSwgc2l6ZSA9IGRncikpICsgCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFjZV9ncm91cF9uYW1lLCBzaXplID0gZGdyLCBmaWx0ZXIgPSBwZXJjZW50X3JhbmsoZGdyKSA+PSAwLjUgKSwgcmVwZWwgPSBUUlVFKSArCiAgdGhlbWVfdm9pZCgpICsKICBsYWJzKHRpdGxlID1wYXN0ZSgnVGVjaG5vbG9neSBTcGFjZSAoYWxsIE5vcmRpY3MpJyksCiAgICAgICBzdWJ0aXRsZSA9ICdOb2RlcyA9IE5BQ0UgMiBJbmR1c3RyaWVzLiBFZGdlczogUmVsYXRlZG5lc3MnKQpgYGAKCiMgU3BlY2lhbGl6YXRpb24gZGV2ZWxvcG1lbnQKCmBgYHtyfQojIGRhdGFmcmFtZSB3aXRoIHRlY2hub2xvZ3kgcmVsYXRlZG5lc3MgZWRnZWxpc3QKdGVjaF9yZWwgPC0gZ190ZWNoICVFPiUKICBtdXRhdGUoZnJvbV9uYWNlID0gLk4oKSRuYW1lW2Zyb21dLAogICAgICAgICB0b19uYWNlID0gLk4oKSRuYW1lW3RvXSkgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgbXV0YXRlKGZyb20gPSBmcm9tX25hY2UgJT4lIGFzLmNoYXJhY3RlcigpLAogICAgICAgICB0byA9IHRvX25hY2UgJT4lIGFzLmNoYXJhY3RlcigpLAogICAgICAgICBwY3RfcmFuayA9IHdlaWdodCAlPiUgcGVyY2VudF9yYW5rKCkpICU+JQogIGFycmFuZ2UoZnJvbSwgdG8pIAoKdGVjaF9yZWwgJTw+JQogIGJpbmRfcm93cyh0ZWNoX3JlbCAlPiUgCiAgICAgICAgICAgICAgcmVuYW1lKGZyb21fbmV3ID0gdG8sIHRvX25ldyA9IGZyb20pICU+JSAKICAgICAgICAgICAgICByZW5hbWUoZnJvbSA9IGZyb21fbmV3LCB0byA9IHRvX25ldykgJT4lCiAgICAgICAgICAgICAgcmVsb2NhdGUoZnJvbSwgdG8pKSAlPiUKICBkaXN0aW5jdChmcm9tLCB0bywgLmtlZXBfYWxsID0gVFJVRSkKYGBgCgpgYGB7cn0KIyBEYXRhZnJhbWUgd2l0aCByZWdpb25zIGFuZCB0ZWNobm9sb2d5IGZpZWxkcwp0ZWNoX2RldiA8LSByZWdpb25fUlRBICU+JQogIHNlbGVjdChwZXJpb2QsIG51dHMsIG5hY2VfZ3JvdXAsIFlfdGFnLCBuX3RlY2hfcmVnaW9uLCBydGEsIHJ0YV9iaW4pICU+JQogIGFycmFuZ2UobnV0cywgbmFjZV9ncm91cCwgWV90YWcsIHBlcmlvZCkgCmBgYAoKYGBge3J9CnAxIDwtIHJlZ2lvbl9SVEEgJT4lCiAgc2VtaV9qb2luKHRvcF9yZWdpb25zLCBieSA9ICdudXRzJykgJT4lCiAgZ3JvdXBfYnkobnV0cywgcGVyaW9kLCBZX3RhZykgJT4lCiAgc3VtbWFyaXNlKG5fc3BlYyA9IHJ0YV9iaW4gJT4lIHN1bShuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBuX3NwZWNfY291bnQgPSAobl90ZWNoX3JlZ2lvbiAqIHJ0YV9iaW4pICU+JSBzdW0obmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgSEhJID0gc3VtKChuX3RlY2hfcmVnaW9uL3N1bShuX3RlY2hfcmVnaW9uKSAqIDEwMCleMikgKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgI2dyb3VwX2J5KG51dHMsIHBlcmlvZCkgJT4lCiAgI3N1bW1hcmlzZShZX3NoYXJlID0gc3VtKFlfdGFnICogbl9zcGVjLCBuYS5ybSA9IFRSVUUpIC8gc3VtKG5fc3BlYywgbmEucm0gPSBUUlVFKSwKICAjICAgICAgICAgIFlfY291bnQgPSBzdW0oWV90YWcgKiBuX3NwZWNfY291bnQsIG5hLnJtID0gVFJVRSkpICU+JQogICN1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKG51dHNfcGVyaW9kID0gcGFzdGUobnV0cywgJ1AnLCBwZXJpb2QpKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gWV90YWcsIHZhbHVlc19mcm9tID0gYyhuX3NwZWMsIG5fc3BlY19jb3VudCwgSEhJKSwgdmFsdWVzX2ZpbGwgPSAwLCBuYW1lc19wcmVmaXggPSAnWV90YWdfJykgCgpwMiA8LSBwMSAlPiUgCiAgc2VsZWN0KHBlcmlvZCwgbnV0cywgbl9zcGVjX1lfdGFnX0ZBTFNFLCBuX3NwZWNfWV90YWdfVFJVRSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHBlcmlvZCwgdmFsdWVzX2Zyb20gPSBjKG5fc3BlY19ZX3RhZ19GQUxTRSwgbl9zcGVjX1lfdGFnX1RSVUUpKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpwMSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBuX3NwZWNfWV90YWdfRkFMU0UsIHkgPSBuX3NwZWNfWV90YWdfVFJVRSkpICsKICBnZW9tX3BvaW50KGFlcyhzaXplID0gbl9zcGVjX2NvdW50X1lfdGFnX1RSVUUsIGNvbCA9IEhISV9ZX3RhZ19UUlVFKSkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBudXRzKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjkpLCBhbHBoYSA9IDAuNzUpICsKICBnZW9tX3NlZ21lbnQoZGF0YSA9IHAyLCAKICAgICAgICAgICAgICAgYWVzKHggPSBuX3NwZWNfWV90YWdfRkFMU0VfMSwKICAgICAgICAgICAgICAgICAgIHkgPSBuX3NwZWNfWV90YWdfVFJVRV8xLAogICAgICAgICAgICAgICAgICAgeGVuZCA9IG5fc3BlY19ZX3RhZ19GQUxTRV8yLAogICAgICAgICAgICAgICAgICAgeWVuZCA9IG5fc3BlY19ZX3RhZ19UUlVFXzIsCiAgICAgICAgICAgICAgICAgICBzaXplID0gMSksCiAgICAgICAgICAgICAgIGFscGhhID0gMC4xNSwKICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuNSwgImNtIiksIHR5cGUgPSAiY2xvc2VkIiksCiAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIobG93ID0gInNreWJsdWUiLCBtaWQgPSAneWVsbG93JywgaGlnaCA9ICJyZWQiLCBtaWRwb2ludCA9IDEpICsKICBsYWJzKHRpdGxlID0gJycsIAogICAgICAgc3VidGl0bGUgPSAnJywKICAgICAgIG5vdGUgPSAnJywKICAgICAgIHggPSAnTiBub24tZ3JlZW4gc3BlY2lhbGl6YXRpb25zJywKICAgICAgIHkgPSAnTiBncmVlbiBzcGVjaWFsaXphdGlvbnMnLAogICAgICAgc2l6ZSA9ICdOIGdyZWVuIHBhdGVudHMnLAogICAgICAgY29sID0gJ0hISSBncmVlbiBwYXRlbnRzJykgCmBgYAoKYGBge3J9CnJtKHAyLCBwMikKYGBgCgojIEFuYWx5c2lzIGZvciBleGlzdGluZyBncmVlbiBwYXRoczoKCmBgYHtyfQpzZWxlY3RfcmVnaW9uc19ncmVlbiA8LSB0ZWNoX2RldiAlPiUKICBncm91cF9ieShudXRzLCBwZXJpb2QpICU+JQogIHN1bW1hcmlzZShncmVlbiA9ICBzdW0oWV90YWcgKiBydGEsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIGdyZWVuX2JpbiA9ICBzdW0oWV90YWcgKiBydGFfYmluLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBuX3RlY2hfcmVnaW9uID0gIHN1bShuX3RlY2hfcmVnaW9uLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBuX2dyZWVuX3JlZ2lvbiA9ICBzdW0oWV90YWcgKiBuX3RlY2hfcmVnaW9uLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBuX2dyZWVuX3J0YSA9ICBzdW0oWV90YWcgKiBuX3RlY2hfcmVnaW9uICogcnRhX2JpbiwgbmEucm0gPSBUUlVFKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGZpbHRlcihuX2dyZWVuX3J0YSA+PSAxMDAsCiAgICAgICAgIGdyZWVuX2JpbiA+PSAxLAogICAgICAgICBwZXJpb2QgPT0gJzEnKSAlPiUKICBzZWxlY3QobnV0cykKYGBgCgpgYGB7cn0KdGVjaF9kZXYgJTw+JSAKICBncm91cF9ieShudXRzLCBuYWNlX2dyb3VwLCBZX3RhZykgJT4lCiAgbXV0YXRlKHJ0YV9kZXYgPSBjYXNlX3doZW4oCiAgICBydGFfYmluIDwgbGFnKHJ0YV9iaW4sIDEpICB+IC0xLAogICAgcnRhX2JpbiA9PSBsYWcocnRhX2JpbiwgMSkgIH4gMCwKICAgIHJ0YV9iaW4gPiBsYWcocnRhX2JpbiwgMSkgIH4gMSAKICApKSAlPiUKICB1bmdyb3VwKCkKYGBgCgpgYGB7cn0KdGVjaF9zcGVjX2RldiA8LSB0ZWNoX2RldiAlPiUKICBmaWx0ZXIobl90ZWNoX3JlZ2lvbiA+PSA1MCkgJT4lCiAgZ3JvdXBfYnkobnV0cywgWV90YWcpICU+JQogIHN1bW1hcmlzZShydGFfZGV2ID0gcnRhX2RldiAlPiUgc3VtKG5hLnJtID0gVFJVRSkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gWV90YWcsIHZhbHVlc19mcm9tID0gcnRhX2RldiwgdmFsdWVzX2ZpbGwgPSAwLCBuYW1lc19wcmVmaXggPSAnWV9zcGVjXycpCmBgYAoKYGBge3J9CnRlY2hfcmVsX2RldiA8LSB0ZWNoX3JlbCAlPiUgCiAgc2VsZWN0KGZyb20sIHRvLCB3ZWlnaHQpICU+JQogIGxlZnRfam9pbih0ZWNoX2RldiAlPiUgZGlzdGluY3QobmFjZV9ncm91cCwgbnV0cyksIGJ5ID0gYygnZnJvbScgPSAnbmFjZV9ncm91cCcpKSAlPiUKICAjIGZpbHRlciBmb3IgcnRhIGluIHBlcmlvZCAxCiAgaW5uZXJfam9pbih0ZWNoX2RldiAlPiUgZmlsdGVyKHBlcmlvZCA9PSAnMScsIHJ0YV9iaW4gPT0gMSkgJT4lIHNlbGVjdChuYWNlX2dyb3VwLCBudXRzLCBZX3RhZyksIGJ5ID0gYygndG8nID0gJ25hY2VfZ3JvdXAnLCAnbnV0cycpKSAlPiUKICAjIGZpbHRlciBmb3IgbmV3IGdyZWVuIHNwZWNpYWxpemF0aW9uIGluIHBlcmlvZCAyCiAgc2VtaV9qb2luKHRlY2hfZGV2ICU+JSBmaWx0ZXIocGVyaW9kID09ICcyJywgcnRhX2JpbiA9PSAxLCBydGFfZGV2ID09IDEsIFlfdGFnID09IFRSVUUpLCBieSA9IGMoJ2Zyb20nID0gJ25hY2VfZ3JvdXAnLCAnbnV0cycpKSAlPiUKICByZW5hbWUobmFjZV9ncm91cCA9IGZyb20sIHJlbGF0ZWRfdGVjaG4gPSB0bykgJT4lCiAgZ3JvdXBfYnkobnV0cywgbmFjZV9ncm91cCwgWV90YWcpICU+JQogIHN1bW1hcmlzZShyZWxfbWF4ID0gd2VpZ2h0ICU+JSBtYXgoKSwKICAgICAgICAgICAgcmVsX3N1bSA9IHdlaWdodCAlPiUgc3VtKCksCiAgICAgICAgICAgIHJlbF9tZWFuID0gd2VpZ2h0ICU+JSBtZWFuKCkpICU+JQogIHVuZ3JvdXAoKQpgYGAKCmBgYHtyfQp0ZWNoX3JlbF9kZXYgJT4lCiAgZ3JvdXBfYnkobnV0cywgWV90YWcpICU+JQogIHN1bW1hcmlzZShyZWwgPSByZWxfbWF4ICU+JSBtZWFuKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gWV90YWcsIHZhbHVlc19mcm9tID0gcmVsLCBuYW1lc19wcmVmaXggPSAnWV8nLCB2YWx1ZXNfZmlsbCA9IDApICU+JQogIGxlZnRfam9pbih0ZWNoX2RldiAlPiUgZmlsdGVyKFlfdGFnID09IFRSVUUsIHBlcmlvZCA9PSAnMicsIHJ0YV9iaW4gPT0gMSkgJT4lIHNlbGVjdChudXRzICwgbl90ZWNoX3JlZ2lvbikgJT4lIGNvdW50KG51dHMsIHd0ID0gbl90ZWNoX3JlZ2lvbiksIGJ5ID0gYygnbnV0cycpKSAlPiUKICBtdXRhdGUoY291bnRyeSA9IG51dHMgJT4lIHN0cl9zdWIoMSwyKSkgJT4lCiAgI3NlbWlfam9pbih0b3BfcmVnaW9ucywgYnkgPSAnbnV0cycpICU+JQogIGZpbHRlcigwLjUgPD0gcGVyY2VudF9yYW5rKG4pKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBZX0ZBTFNFLCB5ID0gWV9UUlVFLCBzaXplID0gbikpICsKICBnZW9tX3BvaW50KGFlcyhjb2wgPSBjb3VudHJ5KSkgKwogIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBudXRzKSwgYm94LnBhZGRpbmcgPSAwLjUsIG1heC5vdmVybGFwcyA9IEluZikgKwogICAgbGFicyh0aXRsZSA9ICdOZXcgZ3JlZW4gc3BlY2lhbGl6YXRpb24gcGVyaW9kIDInLCAKICAgICAgIHN1YnRpdGxlID0gJ0J5IG51dHMgcmVnaW9ucycsCiAgICAgICBub3RlID0gJ1JlbGF0ZWRuZXNzIGlzIHRoZSBtZWFuIG92ZXIgYWxsIG5ldyBncmVlbiBzcGVjaWFsaXphdGlvbnMsIHBlciBncmVlbiBzcGVjaWFsaXphdGlvbiBsYXJnZXN0IHJlbGF0ZWRuZXNzIHRvIGZvcm1lciBzcGVjaWFsaXphdGlvbiBjb3VudGVkJywKICAgICAgIHggPSAnUmVsYXRlZG5lc3Mgbm9uLWdyZWVuJywKICAgICAgIHkgPSAnUmVsYXRlZG5lc3MgZ3JlZW4nLAogICAgICAgc2l6ZSA9ICdOIGdyZWVuIHBhdGVudHMnKSAKYGBgCgpgYGB7cn0KdGVjaF9yZWxfZGV2ICU+JQogIGdyb3VwX2J5KG51dHMsIG5hY2VfZ3JvdXAsIFlfdGFnKSAlPiUKICBzdW1tYXJpc2UocmVsID0gcmVsX21heCAlPiUgbWVhbigpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFlfdGFnLCB2YWx1ZXNfZnJvbSA9IHJlbCwgbmFtZXNfcHJlZml4ID0gJ1lfJywgdmFsdWVzX2ZpbGwgPSAwKSAlPiUKICBsZWZ0X2pvaW4odGVjaF9kZXYgJT4lIGZpbHRlcihZX3RhZyA9PSBUUlVFLCBwZXJpb2QgPT0gJzInLCBydGFfYmluID09IDEpICU+JSBzZWxlY3QobnV0cywgbmFjZV9ncm91cCwgbl90ZWNoX3JlZ2lvbikgJT4lIGNvdW50KG51dHMsIG5hY2VfZ3JvdXAsIHd0ID0gbl90ZWNoX3JlZ2lvbiksIGJ5ID0gYygnbnV0cycsICduYWNlX2dyb3VwJykpICU+JQogIG11dGF0ZShjb3VudHJ5ID0gbnV0cyAlPiUgc3RyX3N1YigxLDIpKSAlPiUKICBzZW1pX2pvaW4odG9wX3JlZ2lvbnMsIGJ5ID0gJ251dHMnKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBZX0ZBTFNFLCB5ID0gWV9UUlVFLCBzaXplID0gbikpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBuYWNlX2dyb3VwKSwgYm94LnBhZGRpbmcgPSAwLjUpICsKICBmYWNldF93cmFwKHZhcnMobnV0cykpICsKICAgIGxhYnModGl0bGUgPSAnTmV3IGdyZWVuIHNwZWNpYWxpemF0aW9uIHBlcmlvZCAyJywgCiAgICAgICBzdWJ0aXRsZSA9ICdCeSBudXRzIHJlZ2lvbnMnLAogICAgICAgbm90ZSA9ICdSZWxhdGVkbmVzcyBpcyB0aGUgbWVhbiBvdmVyIGFsbCBuZXcgZ3JlZW4gc3BlY2lhbGl6YXRpb25zLCBwZXIgZ3JlZW4gc3BlY2lhbGl6YXRpb24gbGFyZ2VzdCByZWxhdGVkbmVzcyB0byBmb3JtZXIgc3BlY2lhbGl6YXRpb24gY291bnRlZCcsCiAgICAgICB4ID0gJ1JlbGF0ZWRuZXNzIG5vbi1ncmVlbicsCiAgICAgICB5ID0gJ1JlbGF0ZWRuZXNzIGdyZWVuJywKICAgICAgIHNpemUgPSAnTiBncmVlbiBwYXRlbnRzJykgCmBgYAoKCgoKKiBMYWJlbCAybmQgZmlndXJlIG9uIGdyZWVuLCBsYWJlbCBjb2luY2lkaW5nLCBtYXliZSBydGEsIHNoYXJlIG9yIGdyb3d0aAoKCgoKCgoKCjwhLS0tClhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWApYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFgKWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYClhYWFhYWFhYWFhYWFhYWFhYWCBPTEQgQU5BTFlTSVMgClhYWFhYWFhYWFhYWFhYWFhYWCBPTEQgQU5BTFlTSVMgClhYWFhYWFhYWFhYWFhYWFhYWCBPTEQgQU5BTFlTSVMgClhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWApYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFgKWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYCi0tLT4KCiMgRGF0YXZpegoKYGBge3J9CnJlZ2lvbnMgPC0gcmVnaW9uX1JUQSAlPiUgZGlzdGluY3QobnV0cykgJT4lIHB1bGwobnV0cykKYGBgCgoKYGBge3IsIGZpZy53aWR0aD0xNSwgZmlnLmhlaWdodD0gMTB9CmkgPSAxOyBwbGFjZSA8LSByZWdpb25zW2ldCnRpbWUgPSAgJzEnCgpnX3RlY2ggJU4+JQogIGxlZnRfam9pbihyZWdpb25fUlRBICU+JSBmaWx0ZXIobnV0cyA9PSBwbGFjZSwgcGVyaW9kID09IHRpbWUpICU+JSBzZWxlY3QodGVjaG5fZmllbGRfbnIsIHJjYSwgcmNhX1ksIG5fdGVjaF9yZWdpb24pLCBieSA9IGMoIm5hbWUiID0gInRlY2huX2ZpZWxkX25yIikpICU+JQogIGdncmFwaChsYXlvdXQgPSBjb29yZHNfdGVjaCkgKyAKICBnZW9tX2VkZ2VfbGluayhhZXMod2lkdGggPSB3ZWlnaHQpLCBhbHBoYSA9IDAuMiwgY29sb3VyID0gImdyZXkiKSArIAogIGdlb21fbm9kZV9wb2ludChhZXMoY29sb3VyID0gcmNhLCBzaXplID0gbl90ZWNoX3JlZ2lvbikpICsgCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gdGVjaG5fZmllbGRfbmFtZSwgc2l6ZSA9IHJjYSwgZmlsdGVyID0gcmNhID49IDEpLCByZXBlbCA9IFRSVUUpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIobG93ID0gInNreWJsdWUiLCBtaWQgPSAneWVsbG93JywgaGlnaCA9ICJyZWQiLCBtaWRwb2ludCA9IDEpICsKICB0aGVtZV9ncmFwaCgpICsKICBsYWJzKHRpdGxlID1wYXN0ZSgiVGVjaG5vbG9neSBTcGFjZToiLCBwbGFjZSwgJ1BlcmlvZCcsIHRpbWUsIHNlcCA9ICIgIiksCiAgICAgICBzdWJ0aXRsZSA9ICdOb2RlcyA9IFRlY2hub2xvZ3kgZmllbGRzLiBFZGdlczogUmVsYXRlZG5lc3MsIENvbG9yID0gUlRBJykKYGBgCg==